package com.maschinenstuermer.profiler.transform;

import java.lang.reflect.Method;

import org.ow2.util.asm.MethodVisitor;
import org.ow2.util.asm.Type;
import org.ow2.util.asm.commons.AdviceAdapter;

import com.maschinenstuermer.profiler.model.TraceModelBuilder;

class ProfilingAdviceAdapter extends AdviceAdapter {
	private static final String TRACE_MODEL_BUILDER_CLAZZ = 
		Type.getInternalName(TraceModelBuilder.class);
	private static final Method ENTER_METHOD;
	private static final Method EXIT_METHOD;
	
	static {
		try {
			ENTER_METHOD = TraceModelBuilder.class.getDeclaredMethod("enterMethod", String.class);
			EXIT_METHOD = TraceModelBuilder.class.getDeclaredMethod("exitMethod");
		} catch (Exception e) {
			throw new IllegalStateException(e);
		}
	}

	private final String signature;
	
	public ProfilingAdviceAdapter(final MethodVisitor mv, final int access, 
			final String name, final String description, final String className) {
		super(mv, access, name, description);
		signature = className + "." + name + 
			MethodDescriptionConverter.convert(description);
	}

	@Override
	protected void onMethodEnter() {
		TraceModelBuilder.profile(signature);
		mv.visitLdcInsn(signature);
		mv.visitMethodInsn(INVOKESTATIC, TRACE_MODEL_BUILDER_CLAZZ, 
				ENTER_METHOD.getName(), Type.getMethodDescriptor(ENTER_METHOD));
	}
	
	@Override
	protected void onMethodExit(int arg0) {
		mv.visitMethodInsn(INVOKESTATIC, TRACE_MODEL_BUILDER_CLAZZ, 
				EXIT_METHOD.getName(), Type.getMethodDescriptor(EXIT_METHOD));
	}
	
	@Override
	public void visitMaxs(int maxStack, int maxLocals) {
		super.visitMaxs(maxStack + 1, maxLocals);
	}
}
